using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using UnityEngine;

public class GGUDPNetworkServer : BehaviourSingleton<GGUDPNetworkServer>
{
	public class UdpState
	{
		public IPEndPoint endPoint;

		public UdpClient client;

		public UdpState()
		{
			client = new UdpClient();
		}
	}

	public const int startingAtPort = 7000;

	public const int maxNumberOfPortsToCheck = 10;

	public List<MessageHandler> handlers = new List<MessageHandler>();

	private UdpState myState;

	private int currentId = -1;

	public void StartServer()
	{
		myState = new UdpState();
		myState.client.EnableBroadcast = true;
		myState.client.ExclusiveAddressUse = true;
		myState.client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
		bool flag = false;
		for (int i = 7000; i <= 7010; i++)
		{
			if (flag)
			{
				break;
			}
			try
			{
				myState.endPoint = new IPEndPoint(IPAddress.Any, i);
				myState.client.Client.Bind(myState.endPoint);
				StartCoroutine(DoReceieveMessages(myState));
				flag = true;
				Debug.Log("listening at: " + myState.endPoint.ToString());
			}
			catch (Exception)
			{
			}
		}
		if (!flag)
		{
			Debug.Log("Didn't find available port");
		}
		currentId = UnityEngine.Random.Range(1, 1000);
	}

	public int NextClientId()
	{
		return ++currentId;
	}

	public void EndServer()
	{
		StopAllCoroutines();
		foreach (MessageHandler handler in handlers)
		{
			handler.OnRemovedFromServer(this);
		}
		handlers.Clear();
		if (myState != null)
		{
			myState.client.Close();
		}
	}

	private IEnumerator DoReceieveMessages(UdpState myState)
	{
		while (true)
		{
			IAsyncResult asyncHandle = myState.client.BeginReceive(OnReceiveComplete, myState);
			while (!asyncHandle.IsCompleted)
			{
				yield return null;
			}
			try
			{
				byte[] data = myState.client.EndReceive(asyncHandle, ref myState.endPoint);
				UDPMessageBase uDPMessageBase = new UDPMessageBase();
				uDPMessageBase.DeserializeFromBytes(data);
				uDPMessageBase.senderAddress = new GGIPAddress(myState.endPoint.Address);
				uDPMessageBase.senderPort = myState.endPoint.Port;
				MessageHandler messageHandler = FindMessageHandlerForMessage(uDPMessageBase);
				if (messageHandler != null)
				{
					messageHandler.OnMessageReceived(uDPMessageBase);
				}
			}
			catch (Exception ex)
			{
				Debug.LogError("exception: " + ex);
			}
		}
	}

	public static void OnReceiveComplete(IAsyncResult ar)
	{
	}

	public static void OnSendComplete(IAsyncResult ar)
	{
		UdpClient udpClient = (UdpClient)ar.AsyncState;
		try
		{
			int num = udpClient.EndSend(ar);
		}
		catch (Exception ex)
		{
			SocketException ex2 = ex as SocketException;
			if (ex2 != null)
			{
				Debug.Log("Sock Error Code " + ex2.ErrorCode);
			}
			Debug.LogError(ex);
		}
	}

	public void SendBroadcast(byte[] data)
	{
		StartCoroutine(DoBroadcastMessage(IPAddress.Broadcast, data));
	}

	public void SendMessage(GGIPAddress destination, int port, byte[] data)
	{
		IPEndPoint endPoint = new IPEndPoint(destination.ipAddress, port);
		IAsyncResult asyncResult = myState.client.BeginSend(data, data.Length, endPoint, OnSendComplete, myState.client);
	}

	private IEnumerator DoBroadcastMessage(IPAddress destination, byte[] data)
	{
		for (int port = 7000; port <= 7010; port++)
		{
			IPEndPoint destEnd = new IPEndPoint(destination, port);
			IAsyncResult asyncHandle = myState.client.BeginSend(data, data.Length, destEnd, OnSendComplete, myState.client);
			while (!asyncHandle.IsCompleted)
			{
				yield return null;
			}
		}
	}

	public void AddHandler(MessageHandler handler)
	{
		handlers.Add(handler);
		handler.OnAddedToServer(this);
	}

	public void RemoveHandler(MessageHandler handler)
	{
		handlers.Remove(handler);
		handler.OnRemovedFromServer(this);
	}

	private MessageHandler FindMessageHandlerForMessage(UDPMessageBase message)
	{
		foreach (MessageHandler handler in handlers)
		{
			if (handler.CanAcceptMessage(message))
			{
				return handler;
			}
		}
		return null;
	}
}
